﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Meta.Numerics.Statistics.Distributions;

namespace ExcelAddIn1
{
    /**
     * Implementation of a linear correlation test.
     */
    class Test_Correlation : Test
    {
        public Test_Correlation(DataContainer data)
        {
            this.data = data;
            res = new List<String>();
        }

        public override string GetInfo()
        {
            String s = "Calculates the linear correlation coefficient (Pearson's correlation coefficient) between two datasets. ";
            s += "Requires that the datasets are normally distributed.";
            return s;
        }

        public override void RunTest()
        {
            res.Add("Correlation coefficient");
            
            //Error check
            if (data.GetNoSets() < 2)
            {
                res.Add("At least two datasets is required!");
                return;
            }

            for (int i1 = 0; i1 < data.GetNoSets(); i1++)
            {
                for (int i2 = 0; i2 < data.GetNoSets(); i2++)
                {
                    if (i1 != i2 && i1 < i2)
                    {
                        RunTest(i1, i2);
                    }
                }
            }
        }

        public void RunTest(int i1, int i2)
        {
            DataSet d1 = data.GetDataSet(i1);
            DataSet d2 = data.GetDataSet(i2);

            double n = (double)d1.GetN();

            //Error check 2
            if (d1.GetN() != d2.GetN())
            {
                res.Add("Both datasets must have equal sample sizes!");
                return;
            }

            double sumX = 0.0;
            double sumY = 0.0;
            double sumXY = 0.0;
            double sumX2 = 0.0;
            double sumY2 = 0.0;

            for (int i = 0; i < n; i++)
            {
                double x = d1.GetValue(i);
                double y = d2.GetValue(i);

                sumX += x;
                sumY += y;
                sumXY += x * y;
                sumX2 += Math.Pow(x, 2);
                sumY2 += Math.Pow(y, 2);
            }

            //Correlation coefficient
            double r = (n * sumXY - sumX * sumY) / Math.Sqrt((n * sumX2 - Math.Pow(sumX, 2)) * (n * sumY2 - Math.Pow(sumY, 2)));

            //Hypothesis testing
            //T-score
            double T = r / Math.Sqrt((1 - Math.Pow(r, 2)) / (n - 2));

            //Find critical t
            double DF = n - 2.0;
            StudentDistribution tdist = new StudentDistribution(DF);
            double TcLow = tdist.InverseLeftProbability(alpha / 2.0);
            double TcHigh = tdist.InverseRightProbability(alpha / 2.0);

            //Calculate P-value
            double p = tdist.RightProbability(T) * 2.0;

            //Results
            res.Add(";" + d1.GetName() + ";" + d2.GetName() + ";-");
            res.Add("N;" + d1.GetN() + ";" + d2.GetN() + ";-");
            res.Add("Mean;" + d1.GetMean().ToString("F2") + ";" + d2.GetMean().ToString("F2"));
            res.Add("StDev;" + d1.GetStDev().ToString("F2") + ";" + d2.GetStDev().ToString("F2"));
            res.Add("DoF;" + (int)DF);
            res.Add("R;" + r.ToString("F2") + ";;-");
            res.Add("α;" + alpha);
            res.Add("P-value;" + p.ToString("F5"));
            res.Add("T-score;" + T.ToString("F2"));
            res.Add("T-crit;" + TcHigh.ToString("F2"));
            if (T < TcLow || T > TcHigh)
            {
                res.Add("Result;Significant correlation at level " + p.ToString("F3"));
            }
            else
            {
                res.Add("Result;No correlation (significance level " + p.ToString("F3") + ")");
            }
            res.Add(";;;-");
        }
    }
}
